package com.gecba.modular.shiro.filter;

import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.InvalidRequestFilter;
import org.apache.shiro.web.filter.mgt.DefaultFilter;
import org.apache.shiro.web.filter.mgt.FilterChainManager;
import org.apache.shiro.web.filter.mgt.FilterChainResolver;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.mgt.WebSecurityManager;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.springframework.beans.factory.BeanInitializationException;

import javax.servlet.Filter;
import java.util.Map;
import java.util.Objects;

/**
 * @author ChenBo
 * @className CustomShiroFilterFactoryBean
 * @date 2021/9/4
 */
@Slf4j
public class CustomShiroFilterFactoryBean extends ShiroFilterFactoryBean {

    /**
     *
     *@author ChenBo
     *@date 2021/9/4
     */
    @Override
    public Class getObjectType() {
        return SpringShiroFilter.class;
    }


    /**
     *
     *@author ChenBo
     *@date 2021/9/4
     */
    @Override
    protected AbstractShiroFilter createInstance() throws Exception {
        SecurityManager securityManager = getSecurityManager();
        if(Objects.isNull(securityManager)){
            throw new BeanInitializationException("SecurityManager property must be set.");
        }

        if(!(securityManager instanceof WebSecurityManager)){
            throw new BeanInitializationException("The security manager does not implement the WebSecurityManager interface.");
        }

        FilterChainManager filterChainManager = createFilterChainManager();
        PathMatchingFilterChainResolver pathMatchingFilterChainResolver = new PathMatchingFilterChainResolver();
        pathMatchingFilterChainResolver.setFilterChainManager(filterChainManager);

        Map<String, Filter> filterMap = filterChainManager.getFilters();
        Filter filter = filterMap.get(DefaultFilter.invalidRequest.name());
        if(filter instanceof InvalidRequestFilter){
            InvalidRequestFilter invalidRequestFilter = (InvalidRequestFilter)filter;
            // 设置false跳过URL携带中文400，servletPath中文校验bug
            invalidRequestFilter.setBlockNonAscii(false);
        }
        WebSecurityManager webSecurityManager = (WebSecurityManager) securityManager;
        return new SpringShiroFilter(webSecurityManager,pathMatchingFilterChainResolver);
    }

    /**
     *
     *@author ChenBo
     *@date 2021/9/4
     */
    private static final class SpringShiroFilter extends AbstractShiroFilter{
        SpringShiroFilter(WebSecurityManager webSecurityManager,FilterChainResolver filterChainResolver){
            if(Objects.isNull(webSecurityManager)){
                throw new IllegalArgumentException("WebSecurityManager property cannot be null.");
            }else {
                this.setSecurityManager(webSecurityManager);
                if(Objects.nonNull(filterChainResolver)){
                    this.setFilterChainResolver(filterChainResolver);
                }
            }
        }
    }
}
